﻿// 2022/4/1: 首个版本
// 2022/8/16: 修正拼写
// 2023/10/9: 添加英文注释

using System;
using System.Collections.Generic;
using System.IO;
using System.Xml;
using System.Threading;
using ASEva;
using ASEva.Utility;

namespace CommonSource
{
    class SingleSessionPick
    {
        public string SourceSessionPath { get; set; }
        public string[] SourceSubSessionPaths { get; set; }
        public DateTime SourceSessionID { get; set; }
        public double SourceBeginTime { get; set; }
        public double SourcePickLength { get; set; }
        public string DstSessionPath { get; set; }
        public DateTime DstSessionID { get; set; }
        public Dictionary<String, String> SessionProperties { get; set; }

        public SingleSessionPick()
        {
            SessionProperties = new Dictionary<string, string>();
        }
    }

    class CommonPickOptions
    {
        public bool[] BusChannelFilter { get; set; }
        public bool[] VideoChannelFilter { get; set; }
        public bool AudioFilter { get; set; }
        public bool SignalFilter { get; set; }
        public bool SampleFilter { get; set; }
        public bool MatrixFilter { get; set; }
        public bool EventFilter { get; set; }

        public CommonPickOptions()
        {
            BusChannelFilter = new bool[16];
            VideoChannelFilter = new bool[24];
        }
    }

    class PickConfig
    {
        public String PickID { get; set; }
        public CommonPickOptions Options { get; set; }
        public List<SingleSessionPick> Picks { get; set; }

        public PickConfig()
        {
            Options = new CommonPickOptions();
            Picks = new List<SingleSessionPick>();
        }

        public static PickConfig FromXmlString(String xmlString)
        {
            try
            {
                var output = new PickConfig();

                var xml = new XmlDocument();
                xml.LoadXml(xmlString);

                var root = xml.DocumentElement;
                var rootCP = new AttributeParser(root);
                var pickNodes = root.GetElementsByTagName("pick");

                output.PickID = rootCP.ParseString("pick_id", null);

                var options = output.Options;
                options.AudioFilter = rootCP.ParseBool("audio_filter", "1", false);
                options.SignalFilter = rootCP.ParseBool("signal_filter", "1", false);
                options.SampleFilter = rootCP.ParseBool("sample_filter", "1", false);
                options.MatrixFilter = rootCP.ParseBool("matrix_filter", "1", false);
                options.EventFilter = rootCP.ParseBool("event_filter", "1", false);

                var busFilterComps = rootCP.ParseString("bus_filter", "").Split(',');
                for (int i = 0; i < Math.Min(16, busFilterComps.Length); i++) options.BusChannelFilter[i] = busFilterComps[i] == "1";

                var videoFilterComps = rootCP.ParseString("video_filter", "").Split(',');
                for (int i = 0; i < Math.Min(24, videoFilterComps.Length); i++) options.VideoChannelFilter[i] = videoFilterComps[i] == "1";

                var pickList = output.Picks;
                foreach (XmlElement pickNode in pickNodes)
                {
                    var pickCP = new AttributeParser(pickNode);
                    var pick = new SingleSessionPick();

                    pick.SourceSessionPath = pickCP.ParseString("src_session_path", "");
                    pick.SourceSessionID = DateTime.ParseExact(pickCP.ParseString("src_session_id", ""), "yyyy-MM-dd-HH-mm-ss", null);
                    pick.SourceBeginTime = pickCP.ParseDouble("pick_start", 0);
                    pick.SourcePickLength = pickCP.ParseDouble("pick_length", 0);
                    if (String.IsNullOrEmpty(pick.SourceSessionPath))
                    {
                        var sourceDataRoot = pickCP.ParseString("src_data_root", ""); // core 3.x compatible / 兼容core 3.x
                        if (!String.IsNullOrEmpty(sourceDataRoot)) pick.SourceSessionPath = sourceDataRoot + Path.DirectorySeparatorChar + pick.SourceSessionID.ToString("yyyyMMdd-HH-mm-ss");
                    }
                    if (pick.SourceSessionPath.Length == 0 || !Directory.Exists(pick.SourceSessionPath)) continue;
                    if (pick.SourceBeginTime < 0 || pick.SourcePickLength <= 0) continue;

                    pick.SourceSubSessionPaths = new String[4];
                    for (int i = 0; i < 4; i++)
                    {
                        var path = pickCP.ParseString("src_sub_session_path_" + i, null);
                        pick.SourceSubSessionPaths[i] = path == null ? "" : path;
                    }

                    pick.DstSessionPath = pickCP.ParseString("dst_session_path", "");
                    pick.DstSessionID = pick.SourceSessionID.AddSeconds(Math.Floor(pick.SourceBeginTime));
                    if (String.IsNullOrEmpty(pick.DstSessionPath))
                    {
                        var dstDataRoot = pickCP.ParseString("dst_data_root", ""); // core 3.x compatible / 兼容core 3.x
                        if (!String.IsNullOrEmpty(dstDataRoot)) pick.DstSessionPath = dstDataRoot + Path.DirectorySeparatorChar + pick.DstSessionID.ToString("yyyyMMdd-HH-mm-ss");
                    }
                    if (pick.DstSessionPath.Length == 0) continue;

                    pick.SessionProperties = new Dictionary<string, string>();
                    foreach (XmlElement propNode in pickNode.GetElementsByTagName("property"))
                    {
                        var propCP = new AttributeParser(propNode);
                        var key = propCP.ParseString("key", "");
                        if (key.Length == 0) continue;
                        pick.SessionProperties[key] = propNode.InnerText;
                    }

                    pickList.Add(pick);
                }
                
                return output;
            }
            catch (Exception) { return null; }
        }

        public String ToXmlString()
        {
            var xml = Xml.Create("root");
            var rootCW = new AttributeWriter(xml.DocumentElement);
            rootCW.WriteString("pick_id", PickID);
            rootCW.WriteBool("audio_filter", Options.AudioFilter, "1", "0");
            rootCW.WriteBool("signal_filter", Options.SignalFilter, "1", "0");
            rootCW.WriteBool("sample_filter", Options.SampleFilter, "1", "0");
            rootCW.WriteBool("matrix_filter", Options.MatrixFilter, "1", "0");
            rootCW.WriteBool("event_filter", Options.EventFilter, "1", "0");

            var busFilterTexts = new List<String>();
            var videoFilterTexts = new List<String>();
            for (int i = 0; i < 16; i++) busFilterTexts.Add(Options.BusChannelFilter[i] ? "1" : "0");
            for (int i = 0; i < 24; i++) videoFilterTexts.Add(Options.VideoChannelFilter[i] ? "1" : "0");
            rootCW.WriteString("bus_filter", String.Join(",", busFilterTexts));
            rootCW.WriteString("video_filter", String.Join(",", videoFilterTexts));

            foreach (var pick in Picks)
            {
                var pickNode = xml.DocumentElement.AppendChild(xml.CreateElement("pick")) as XmlElement;
                var pickCW = new AttributeWriter(pickNode);
                pickCW.WriteString("src_session_path", pick.SourceSessionPath);
                pickCW.WriteString("src_session_id", pick.SourceSessionID.ToString("yyyy-MM-dd-HH-mm-ss"));
                pickCW.WriteDouble("pick_start", pick.SourceBeginTime);
                pickCW.WriteDouble("pick_length", pick.SourcePickLength);
                pickCW.WriteString("dst_session_path", pick.DstSessionPath);
                for (int i = 0; i < 4; i++)
                {
                    if (pick.SourceSubSessionPaths[i] != null) pickCW.WriteString("src_sub_session_path_" + i, pick.SourceSubSessionPaths[i]);
                }

                if (pick.SessionProperties != null)
                {
                    foreach (var prop in pick.SessionProperties)
                    {
                        var propNode = pickNode.AppendChild(xml.CreateElement("property")) as XmlElement;
                        propNode.Attributes.Append(xml.CreateAttribute("key")).Value = prop.Key;
                        propNode.InnerText = prop.Value;
                    }
                }
            }

            return xml.InnerXml;
        }
    }
}
